/** biome-ignore-all lint/suspicious/noConsole: allow console.log */
import fs from "node:fs";
import path from "node:path";
import { app } from "electron";
import { Logger, LogLevel } from "./base-logger";

class MainLogger extends Logger {
  private logsDir?: string;
  private loggingEnabled = true; // Enable file logging by default
  private retentionDays = 7; // Keep logs for 7 days

  constructor(
    config: Partial<{
      level: LogLevel;
      enableColors: boolean;
      includeTimestamp: boolean;
      prettyPrintThreshold: number;
      enableFileLogging: boolean;
      retentionDays?: number;
    }> = {},
    context?: Record<string, unknown>,
  ) {
    super(config, context);

    if (config.retentionDays) {
      this.retentionDays = config.retentionDays;
    }

    if (config.enableFileLogging !== false) {
      this.initializeFileLogging();
    }
  }

  private initializeFileLogging(): void {
    try {
      const userData = app?.getPath("userData");
      if (userData) {
        this.logsDir = path.join(userData, "logs");

        // Ensure logs directory exists
        if (!fs.existsSync(this.logsDir)) {
          fs.mkdirSync(this.logsDir, { recursive: true });
        }

        this.loggingEnabled = true;
        this.cleanupOldLogs();
      }
    } catch (error) {
      console.error("Failed to initialize file logging:", error);
    }
  }

  private getDateInfo(): {
    year: string;
    month: string;
    day: string;
    yearMonth: string;
  } {
    const now = new Date();
    const year = now.getFullYear().toString();
    const month = (now.getMonth() + 1).toString().padStart(2, "0");
    const day = now.getDate().toString().padStart(2, "0");
    return {
      year,
      month,
      day,
      yearMonth: `${year}-${month}`,
    };
  }

  private getLogFilePath(level: string): string {
    if (!this.logsDir) throw new Error("Logs directory not initialized");

    const { yearMonth, day } = this.getDateInfo();
    const levelDir = path.join(this.logsDir, yearMonth, day);

    // Ensure the date directory exists
    if (!fs.existsSync(levelDir)) {
      fs.mkdirSync(levelDir, { recursive: true });
    }

    return path.join(levelDir, `${level.toLowerCase()}.log`);
  }

  private cleanupOldLogs(): void {
    if (!this.logsDir) return;

    try {
      const cutoffDate = new Date();
      cutoffDate.setDate(cutoffDate.getDate() - this.retentionDays);

      const monthDirs = fs
        .readdirSync(this.logsDir, { withFileTypes: true })
        .filter((dirent) => dirent.isDirectory())
        .map((dirent) => dirent.name);

      for (const monthDir of monthDirs) {
        const monthPath = path.join(this.logsDir, monthDir);

        // Check if monthDir matches YYYY-MM format
        if (!/^\d{4}-\d{2}$/.test(monthDir)) continue;

        const dayDirs = fs
          .readdirSync(monthPath, { withFileTypes: true })
          .filter((dirent) => dirent.isDirectory())
          .map((dirent) => dirent.name);

        for (const dayDir of dayDirs) {
          const dayPath = path.join(monthPath, dayDir);

          // Check if dayDir matches DD format
          if (!/^\d{2}$/.test(dayDir)) continue;

          // Construct the full date string for comparison
          const fullDateStr = `${monthDir}-${dayDir}`;
          const logDate = new Date(fullDateStr);

          if (logDate < cutoffDate) {
            // Remove the entire day directory
            this.removeDirectory(dayPath);
          }
        }

        // Remove empty month directories
        const remainingDays = fs.readdirSync(monthPath);
        if (remainingDays.length === 0) {
          fs.rmdirSync(monthPath);
        }
      }
    } catch (error) {
      console.error("Failed to cleanup old logs:", error);
    }
  }

  private removeDirectory(dirPath: string): void {
    try {
      const files = fs.readdirSync(dirPath);
      for (const file of files) {
        const filePath = path.join(dirPath, file);
        const stat = fs.statSync(filePath);
        if (stat.isDirectory()) {
          this.removeDirectory(filePath);
        } else {
          fs.unlinkSync(filePath);
        }
      }
      fs.rmdirSync(dirPath);
    } catch (error) {
      console.error(`Failed to remove directory ${dirPath}:`, error);
    }
  }

  private formatForFile(
    level: string,
    message: string,
    context?: Record<string, unknown>,
  ): string {
    const timestamp = new Date().toISOString();
    const contextStr = context ? ` ${JSON.stringify(context)}` : "";
    return `[${timestamp}] ${level}: ${message}${contextStr}`;
  }

  private writeToFile(level: string, logEntry: string): void {
    if (!this.logsDir || !this.loggingEnabled) return;

    try {
      const logFilePath = this.getLogFilePath(level);
      fs.appendFileSync(logFilePath, `${logEntry}\n`, "utf8");
    } catch (error) {
      console.error("Failed to write to log file:", error);
    }
  }

  setLoggingEnabled(enabled: boolean): void {
    this.loggingEnabled = enabled;
  }

  public cleanupLogs(): void {
    this.cleanupOldLogs();
  }

  debug(message: string, context?: Record<string, unknown>): void {
    if (!this.shouldLog(LogLevel.DEBUG)) return;
    super.debug(message, context);
    this.writeToFile("DEBUG", this.formatForFile("DEBUG", message, context));
  }

  info(message: string, context?: Record<string, unknown>): void {
    if (!this.shouldLog(LogLevel.INFO)) return;
    super.info(message, context);
    this.writeToFile("INFO", this.formatForFile("INFO", message, context));
  }

  warn(message: string, context?: Record<string, unknown>): void {
    if (!this.shouldLog(LogLevel.WARN)) return;
    super.warn(message, context);
    this.writeToFile("WARN", this.formatForFile("WARN", message, context));
  }

  error(message: string, context?: Record<string, unknown>): void {
    if (!this.shouldLog(LogLevel.ERROR)) return;
    super.error(message, context);
    this.writeToFile("ERROR", this.formatForFile("ERROR", message, context));
  }

  child(context: Record<string, unknown>): MainLogger {
    const newContext = { ...this.context, ...context };
    const childLogger = new MainLogger(this.config, newContext);
    childLogger.logsDir = this.logsDir;
    childLogger.loggingEnabled = this.loggingEnabled;
    childLogger.retentionDays = this.retentionDays;
    return childLogger;
  }
}

// Create default main logger instance
const mainLogger = new MainLogger({
  level: LogLevel.DEBUG,
  enableColors: true,
  includeTimestamp: true,
  prettyPrintThreshold: 100,
  enableFileLogging: true,
  retentionDays: 7,
});

export function debug(
  message: string,
  context?: Record<string, unknown>,
): void {
  mainLogger.debug(message, context);
}

export function info(message: string, context?: Record<string, unknown>): void {
  mainLogger.info(message, context);
}

export function warn(message: string, context?: Record<string, unknown>): void {
  mainLogger.warn(message, context);
}

export function error(
  message: string,
  context?: Record<string, unknown>,
): void {
  mainLogger.error(message, context);
}

export function setLoggingEnabled(enabled: boolean): void {
  mainLogger.setLoggingEnabled(enabled);
}

export function cleanupLogs(): void {
  mainLogger.cleanupLogs();
}

export { LogLevel, MainLogger };
export default mainLogger;
